package binderipcservicemanager

import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.os.Parcel

class BCAdvancedServiceManagerService : Binder(), IBCAdvancedServiceManager {

    private val mAliveServices = mutableMapOf<String, ServiceEntry>()
    private val mDiedServices = mutableMapOf<String, ServiceEntry>()

    init {
        attachInterface(this, IBCAdvancedServiceManager.descriptor)
    }

    override fun asBinder(): IBinder {
        return this
    }

    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
        when (code) {
            IBCAdvancedServiceManager.TRANSACTION_ADD_SERVICE -> {
                data.enforceInterface(IBCAdvancedServiceManager.descriptor)

                reply?.writeNoException()
                val name = data.readString()
                val readBundle = data.readBundle(javaClass.classLoader)
                val binder = readBundle?.getBinder(name)

                addService(name, binder)

                reply?.writeString(name)
                val writeBundle = Bundle()
                writeBundle.putBinder(name, binder)
                reply?.writeBundle(writeBundle)

                return true
            }
            IBCAdvancedServiceManager.TRANSACTION_GET_SERVICE -> {
                data.enforceInterface(IBCAdvancedServiceManager.descriptor)

                reply?.writeNoException()
                val name = data.readString()
                val binder = getService(name)
                val replyBundle = Bundle()
                replyBundle.putBinder(name, binder)
                reply?.writeBundle(replyBundle)

                return true
            }
            IBCAdvancedServiceManager.TRANSACTION_REMOVE_SERVICE -> {
                data.enforceInterface(IBCAdvancedServiceManager.descriptor)

                reply?.writeNoException()
                val name = data.readString()

                removeService(name)

                reply?.writeString(name)
                return true
            }
        }
        return super.onTransact(code, data, reply, flags)
    }

    override fun addService(name: String?, binder: IBinder?) {
        //不允许重复
        if (mAliveServices.containsKey(name!!)) {
            val item = mAliveServices[name]
            throw RuntimeException(String.format("Service %s has registered by pid: %s, uid: %s", name, item?.callingPid, item?.callingUid))
        }

        val recipient = IBinder.DeathRecipient {
            val item = mAliveServices.remove(name)
            if (item != null) {
                //保存死亡Binder对象
                mDiedServices[name] = item
            }
        }

        //保存Binder
        val item =
            ServiceEntry(name, Binder.getCallingPid(), Binder.getCallingUid(), binder, recipient)
        mAliveServices[name] = item
        mDiedServices.remove(name)

        //死亡通知
        item.linkToDeath()
    }

    override fun getService(name: String?): IBinder? {
        var item = mAliveServices[name]
        if (item == null) {
            item = mDiedServices[name]
        }
        if (item != null) {
            return item.binder
        }
        return null
    }

    override fun removeService(name: String?) {
        val item = mAliveServices.remove(name)
        //取消Binder死亡通知
        item?.unlinkToDeath()
        mDiedServices.remove(name)
    }
}